/** 
 *    
 *  Copyright (C) 2008 Marco Speranza <marco.speranza79@gmail.com>
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
package org.commons.database.jconnectionpool;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.ConnectionPoolDataSource;

import org.apache.log4j.Logger;

/**
 * Classe che crea e gestisce le richieste di connessione al DB
 * 
 * Un tipo uso e':
 * <pre>
 * 	DataBaseManager dbManager = new DataBaseManager(); 	
 *	dbManager.initMySqlConnectionPoolDataSource("jdbc:mysql://localhost:3306/mysql", "user", "pass"); *		
 *	dbManager.setInitialPoolCapacity(100);
 *	dbManager.open();	
 *	Connection c = dbManager.getConnection();
 *	
 *	...doSomething(c);...	
 *
 *	dbManager.releaseConnection(c);
 *	dbManager.close();
 *
 * </pre>
 * 
 * 
 * 
 * @author <a href="mailto:msperanza@users.sourceforge.net">Marco Speranza</a>
 * @version $Id: DataBaseManager.java,v 1.1 2006/08/10 09:48:09 msperanza Exp $
 */
public class DataBaseManager {

	private static Logger log = Logger.getLogger(DataBaseManager.class);
	private PoolConnectionManager poolConnManager;

	private String connectionString;
	private String user;
	private String password;
	private int initialCapacity;

	
	/**
	 * Costruttore di default
	 * 
	 */
	public DataBaseManager() {
		this(null, null, null);
	}

	/**
	 * Costruttore
	 * 
	 * @param connectionString jdbc connection string
	 * @throws SQLException in caso di errore
	 */
	public DataBaseManager(String connectionString) {
		this(connectionString, null, null);
	}

	/**
	 * Costruttore
	 * 
	 * @param connectionString jdbc connection string
	 * @param user db user
	 * @param password db password
	 * @throws SQLException in caso di errore
	 */
	public DataBaseManager(String connectionString, String user, String password) {
		this.connectionString = connectionString;
		this.user = user;
		this.password = password;
	}

	/**
	 * Chiude la connessione con il DB
	 * 
	 * @throws SQLException
	 *             Errore nella chiusura della connessione al DB
	 */
	public void close() throws SQLException {
		log.info("Close connection pool");
		poolConnManager.closePool();
	}

	/**
	 * Torna una connessione nuova, oppure una disponibile al DB
	 * @return <code> java.sql.Connection</code> la connessiona al DB 
	 * @throws SQLException in caso di errore
	 */
	public Connection getConnection() throws SQLException {
		Connection con = poolConnManager.getConnection();		
		return con;
	}

	/**
	 * Inizializza il pool di connessione
	 * 
	 * @param connectionPoolDataSourceClassName
	 *            class name da instanziare
	 * @param connectionString
	 *            jdbc url
	 * @param username
	 *            database username
	 * @param password
	 *            database password
	 * @param initialCapacity
	 *            capacita' iniziale del pool di connessione
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>connectionPoolDataSourceClassName</code>
	 * @throws Exception
	 *             In caso di errore interno
	 */
	public void init(ConnectionPoolDataSource connectionPoolDataSource) {
		poolConnManager = new PoolConnectionManager(connectionPoolDataSource);
	}

	/**
	 * Inizializza il pool di connessione con una capacita' iniziale di default
	 * (60).
	 * 
	 * @param connectionPoolDataSourceClassName
	 *            class name da instanziare
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>connectionPoolDataSourceClassName</code>
	 * @throws Exception
	 *             In caso di errore interno
	 * 
	 */
	public void init(String connectionPoolDataSourceClassName)
			throws ClassNotFoundException, Exception {
		init(connectionPoolDataSourceClassName, getConnectionString(),
				getUser(), getPassword(), 60);
	}

	/**
	 * Inizializza il pool di connessione
	 * 
	 * @param connectionPoolDataSourceClassName
	 *            class name da instanziare
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>connectionPoolDataSourceClassName</code>
	 * @throws Exception
	 *             In caso di errore interno
	 * 
	 */
	public void init(String connectionPoolDataSourceClassName,
			int initialCapacity) throws ClassNotFoundException, Exception {
		init(connectionPoolDataSourceClassName, getConnectionString(),
				getUser(), getPassword(), initialCapacity);
	}

	/**
	 * Inizializza il pool di connessione con una capacita' iniziale di default
	 * (60).
	 * 
	 * @param connectionPoolDataSourceClassName
	 *            class name da instanziare
	 * @param connectionString
	 *            jdbc url
	 * @param username
	 *            database username
	 * @param password
	 *            database password
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>connectionPoolDataSourceClassName</code>
	 * @throws Exception
	 *             In caso di errore interno
	 * 
	 */
	public void init(String connectionPoolDataSourceClassName,
			String connectionString, String username, String password)
			throws ClassNotFoundException, Exception {
		init(connectionPoolDataSourceClassName, connectionString, username,
				password, 60);
	}

	/**
	 * Inizializza il pool di connessione
	 * 
	 * @param connectionPoolDataSourceClassName
	 *            class name da instanziare
	 * @param connectionString
	 *            jdbc url
	 * @param username
	 *            database username
	 * @param password
	 *            database password
	 * @param initialCapacity
	 *            capacita' iniziale del pool di connessione
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>connectionPoolDataSourceClassName</code>
	 * @throws Exception
	 *             In caso di errore interno
	 */
	public void init(String connectionPoolDataSourceClassName,
			String connectionString, String username, String password,
			int initialCapacity) throws ClassNotFoundException, Exception {
		setConnectionString(connectionString);
		setPassword(password);
		setUser(username);

		DefaultConnectionPoolDataSource defaultConnectionPoolDataSource = new DefaultConnectionPoolDataSource(
				connectionPoolDataSourceClassName);
		defaultConnectionPoolDataSource.init(getConnectionString(), getUser(),
				getPassword());
		ConnectionPoolDataSource connectionPoolDataSource = defaultConnectionPoolDataSource
				.getConnectionPoolDataSource();

		poolConnManager = new PoolConnectionManager(connectionPoolDataSource);
		setInitialPoolCapacity(initialCapacity);

	}

	/**
	 * Inizializza il pool di connessione di default per un database Mysql
	 * 
	 * @param connectionString
	 *            jdbc url
	 * @param username
	 *            database username
	 * @param password
	 *            database password
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>DefaultConnectionPoolDataSource.MYSQL_POOL_CLASS_NAME</code>
	 * @throws Exception
	 *             In caso di errore interno
	 */
	public void initMySqlConnectionPoolDataSource(String connectionString,
			String username, String password) throws ClassNotFoundException,
			Exception {
		init(DefaultConnectionPoolDataSource.MYSQL_POOL_CLASS_NAME,
				connectionString, username, password, 60);
	}

	/**
	 * Inizializza il pool di connessione di default per un database Oracle
	 * 
	 * @param connectionString
	 *            jdbc url
	 * @param username
	 *            database username
	 * @param password
	 *            database password
	 * @throws ClassNotFoundException
	 *             lanciata se non esiste la classe
	 *             <code>DefaultConnectionPoolDataSource.ORACLE_POOL_CLASS_NAME</code>
	 * @throws Exception
	 *             In caso di errore interno
	 */
	public void initOracleConnectionPoolDataSource(String connectionString,
			String username, String password) throws ClassNotFoundException,
			Exception {
		init(DefaultConnectionPoolDataSource.ORACLE_POOL_CLASS_NAME,
				connectionString, username, password, 60);
	}

	/**
	 * apre una sessione sul DB utilizzando i dati di classe
	 * 
	 * @throws SQLException
	 *             Errore di connessione al DB
	 */
	public void open() throws SQLException {
		poolConnManager.setInitialPoolCapacity(initialCapacity);
		poolConnManager.createPool();
		log.info("Connect to db done url:" + connectionString + " user:" + user
				+ " pwd:" + password);
	}

	/**
	 * Rilascia una connessione al DB
	 * 
	 * @param conn
	 *            Connessione da rilasciare
	 * @throws SQLException
	 *             Errore nella chiusura della connessione al DB
	 */
	public void releaseConnection(Connection conn) throws SQLException {
		poolConnManager.closeConnection(conn);
	}

	/**
	 * setta la connection string al db
	 * @param connectionString la jdbc connection string
	 */
	public void setConnectionString(String connectionString) {
		this.connectionString = connectionString;
	}

	/**
	 * Setta la capacita' iniziale del pool di connessione.
	 * 
	 * @param initialCapacity
	 *            la capacita' iniziale.
	 */
	public void setInitialPoolCapacity(int initialCapacity) {
		this.initialCapacity = initialCapacity;
	}

	/**
	 * setta la password del database
	 * @param password la password del db
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * setta l'utente del database
	 * @param password l'utente del db
	 */
	public void setUser(String user) {
		this.user = user;
	}

	/**
	 * torna la stringa di connessione jdbc 
	 * @return String la string di connessional db
	 */
	private String getConnectionString() {
		return connectionString;
	}

	private String getPassword() {
		return password;
	}

	int getPoolSize() {
		return poolConnManager.getPoolSize();
	}

	private String getUser() {
		return user;
	}

}
